#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include "Task.hpp"
template <class T>
class ThreadPool
{

private:
    void Lock()
    {
        pthread_mutex_lock(&mutex_);
    }

    void UnLock()
    {
        pthread_mutex_unlock(&mutex_);
    }

    void WakeUp()
    {
        pthread_cond_signal(&cond_);
    }

    void Sleep()
    {
        pthread_cond_wait(&cond_, &mutex_);
    }

     ThreadPool(int cap = deafaultNumber) : cap_(cap), threads_(cap_)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }
    ThreadPool(const ThreadPool<T>&)=delete;
    const ThreadPool<T>& operator=(const ThreadPool<T>&)=delete;

public:
    static const int deafaultNumber = 5;
    class ThreadInof
    {
    public:
        pthread_t id;
        std::string threadName;
    };

    static ThreadPool<T>* GetInstance(int cap = deafaultNumber)
    {
        if(tp_==nullptr)
        {
            tp_=new ThreadPool<T>(cap);
        }
        return tp_;
    }

   
   
    static void *HeadlerTask(void *args)
    {
        ThreadPool<T> *th = static_cast<ThreadPool<T> *>(args);

        while (true)
        {
            // sleep(1);
            std::cout << "new thread wait task" << std::endl;
            th->Lock();
            while (th->tasks_.empty())
            {
                th->Sleep();
            }

            T task = th->Pop();
            th->UnLock();
            task();
        }
    }

    void Start()
    {
        for (int i = 0; i < cap_; i++)
        {
            pthread_create(&(threads_[i].id), nullptr, HeadlerTask, this);
            threads_[i].threadName = "thread" + std::to_string(i);
        }
    }

    void End()
    {
        for (int i = 0; i < cap_; i++)
        {
            pthread_join(threads_[i].id, nullptr);
        }
    }

    void Push(const T &task)
    {
        Lock(); // 给主线程用的
        tasks_.push(task);
        WakeUp();
        UnLock();
    }

    T Pop()
    {
        T task = tasks_.front();
        tasks_.pop();
        return task;
    }

private:
    int cap_;
    std::vector<ThreadInof> threads_;
    std::queue<T> tasks_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;
    static ThreadPool<T>* tp_;
};
template<class T>
ThreadPool<T>* ThreadPool<T>::tp_=nullptr;